# WSL集群环境下安装K3s的PowerShell脚本

# 日志函数
function Log {
    param(
        [string]$Level,
        [string]$Message
    )
    $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    Write-Output "[$Timestamp] [$Level] $Message"
}

# 检查是否为管理员
function Check-Admin {
    if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        Log "ERROR" "请使用管理员权限运行此脚本"
        exit 1
    }
}

# 封装获取 WSL 实例的函数
function Get-WSLInstances {
    try {
        $rawOutput = (wsl -l -q | Out-String).Trim()
        Log "INFO" "wsl -l -q 原始输出: $rawOutput"
        $instancesArray = $rawOutput -split '\r?\n' | ForEach-Object {
            $cleaned = [Regex]::Replace($_.Trim(), '[^\w]', '')
            if ($cleaned -ne "" -and $cleaned -imatch "^(node1|node2|node3)$") {
                $cleaned
            }
        }
        Log "INFO" "分割后的实例数组: $($instancesArray -join ', ')"
        $matchingInstances = $instancesArray | Where-Object { $_ -imatch "^(node1|node2|node3)$" }
        Log "INFO" "匹配到的 WSL 实例: $($matchingInstances -join ', ')"
        return $matchingInstances
    } catch {
        Log "ERROR" "获取 WSL 实例时出错: $_"
        return @()
    }
}

# 安装K3s
function Install-K3s {
    Log "INFO" "开始非交互式安装K3s..."
    
    # 先启动所有匹配的WSL实例
    $instances = Get-WSLInstances
    $wslList = (wsl -l -q | Out-String).Trim() -split '\r?\n' | ForEach-Object { $_.Trim() }
    
    # 重新获取所有WSL实例
    $instances = Get-WSLInstances
    
    if ($instances.Count -eq 0) {
        Log "ERROR" "未找到匹配的WSL实例，无法安装K3s。"
        exit 1
    }
    
    # 强制将 node1 作为主节点
    if ($instances -notcontains "node1") {
        Log "ERROR" "未找到 node1 实例，无法安装 K3s master。"
        exit 1
    }
    $masterNode = "node1"
    
    Log "INFO" "在主节点 $masterNode 上调用 install-k3s-master.sh 安装 K3s server..."
    try {
        Log "INFO" "开始执行 install-k3s-master.sh 脚本..."
        $scriptPath = "f:\move\install-k3s-master.sh"
        if (-not (Test-Path -Path $scriptPath)) {
            Log "ERROR" "install-k3s-master.sh 脚本文件不存在，请检查路径。"
            exit 1
        }
    
        try {
            $fileInfo = Get-Item -Path $scriptPath
            if (-not $fileInfo.IsReadOnly) {
                Log "INFO" "install-k3s-master.sh 文件可访问。"
            } else {
                Log "WARN" "install-k3s-master.sh 文件为只读，可能会影响执行。"
            }
        } catch {
            Log "ERROR" "检查 install-k3s-master.sh 文件权限时出错: $_"
            exit 1
        }
    
        $job = Start-Job -ScriptBlock {
            param($masterNode)
            try {
                # 确保路径在 WSL 环境下正确映射
                $wslScriptPath = "/mnt/f/move/install-k3s-master.sh"
                $process = Start-Process -FilePath "wsl.exe" -ArgumentList "-d $masterNode -u root -e bash -c `"chmod +x $wslScriptPath && $wslScriptPath 2>&1`"" -PassThru -NoNewWindow -RedirectStandardOutput "$PSScriptRoot\install-k3s-master-output.log" -RedirectStandardError "$PSScriptRoot\install-k3s-master-error.log"
                $process.WaitForExit()
                return $process.ExitCode
            } catch {
                $_ | Out-File -FilePath "$PSScriptRoot\install-k3s-master-error.log" -Append
                return -1
            }
        } -ArgumentList $masterNode
    
        # 延长超时时间
        $timeout = 300
        Wait-Job -Job $job -Timeout $timeout | Out-Null
    
        if ($job.State -eq "Running") {
            # 超时则停止作业
            Stop-Job -Job $job
            Log "ERROR" "在主节点 $masterNode 上安装 K3s server 超时，请检查脚本或网络。"
            exit 1
        } else {
            # 获取作业输出和退出码
            $result = Receive-Job -Job $job
            if ($result -eq 0) {
                Log "INFO" "install-k3s-master.sh 脚本成功执行。"
            } else {
                $errorLogPath = "$PSScriptRoot\install-k3s-master-error.log"
                if (Test-Path -Path $errorLogPath) {
                    $errorOutput = Get-Content -Path $errorLogPath -Raw
                    Log "ERROR" "install-k3s-master.sh 脚本执行失败，退出码: $result，错误信息: $errorOutput"
                } else {
                    Log "ERROR" "install-k3s-master.sh 脚本执行失败，退出码: $result，错误日志文件 $errorLogPath 不存在。"
                }
            }
        }
        Log "INFO" "install-k3s-master.sh 脚本执行完成。"
    } catch {
        Log "ERROR" "在主节点 $masterNode 上安装 K3s server 出错: $_"
        exit 1
    }

    # 添加日志，标记开始获取 K3s server token
    Log "INFO" "开始获取 K3s server token..."
    $token = wsl -d $masterNode -u root -e bash -c "cat /var/lib/rancher/k3s/server/node-token"
    # 添加日志，标记获取 K3s server token 完成
    Log "INFO" "获取 K3s server token 完成，token: $token"

    # 添加日志，标记开始获取主节点 IP
    Log "INFO" "开始获取主节点 IP..."
    $maxRetries = 3
    $retryCount = 0
    $masterIP = ""
    do {
        try {
            Log "INFO" "正在进行第 $($retryCount + 1) 次尝试获取主节点 IP..."
            $rawOutput = wsl -d $masterNode -u root -e bash -c "hostname -I | tr -s ' ' '\n' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'"
            $masterIP = $rawOutput.Trim().Split()[0]
            Log "INFO" "本次尝试获取到的主节点 IP 原始输出: $rawOutput"
            Log "INFO" "本次尝试处理后的主节点 IP: $masterIP"
            if ($masterIP -match '^(\d{1,3}\.){3}\d{1,3}$') {
                Log "INFO" "成功获取到有效的主节点 IP 地址: $masterIP"
                break
            } else {
                Log "WARN" "本次尝试获取到的 IP 地址无效: $masterIP"
            }
        } catch {
            $retryCount++
            if ($retryCount -lt $maxRetries) {
                Log "WARN" "获取主节点 IP 失败，正在进行第 $retryCount 次重试..."
                Start-Sleep -Seconds 5
            }
        }
    } while ($retryCount -lt $maxRetries)
    
    if (-not ($masterIP -match '^(\d{1,3}\.){3}\d{1,3}$')) {
        Log "ERROR" "无法获取有效的主节点 IP 地址，安装失败。"
        exit 1
    }
    # 添加日志，标记获取主节点 IP 完成
    Log "INFO" "最终获取到的主节点 IP 地址: $masterIP"

    # 在其他节点上调用 install-k3s-worker.sh 安装 K3s agent
    $workerNodes = $instances | Where-Object { $_ -ne "node1" }
    $installJobs = @()

    foreach ($node in $workerNodes) {
        # 添加日志，标记开始在工作节点安装 K3s agent
        Log "INFO" "开始在工作节点 $node 上调用 install-k3s-worker.sh 安装 K3s agent..."
        
        # 确保 $command 变量被正确赋值，这里确保 $masterIP 正确传递
        if (-not $masterIP) {
            Log "ERROR" "主节点 IP 地址未正确获取，无法在 $node 上安装 K3s agent。"
            continue
        }
        $command = "chmod +x /mnt/f/move/install-k3s-worker.sh && /mnt/f/move/install-k3s-worker.sh --server https://$masterIP:6443 --token $token"
        Log "INFO" "工作节点 $node 即将执行的命令: $command"

        $job = Start-Job -ScriptBlock {
            param($node, $command)
            # 嵌入 Log 函数的逻辑
            function Log {
                param(
                    [string]$Level,
                    [string]$Message
                )
                $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
                Write-Output "[$Timestamp] [$Level] $Message"
            }
            try {
                Log "INFO" "在工作节点 $node 上执行命令: $command"
                $process = Start-Process -FilePath "wsl.exe" -ArgumentList "-d $node -u root -e bash -c `"$command`"" -PassThru -NoNewWindow
                $process.WaitForExit()
                return $process.ExitCode
            } catch {
                Log "ERROR" "在工作节点 $node 上执行命令时出错: $_"
                return -1
            }
        } -ArgumentList $node, $command
        
        $installJobs += $job
    }

    # 等待所有作业完成
    $timeout = 300
    Wait-Job -Job $installJobs -Timeout $timeout | Out-Null

    foreach ($job in $installJobs) {
        $node = $workerNodes[$installJobs.IndexOf($job)]
        if ($job.State -eq "Running") {
            # 超时则停止作业
            Stop-Job -Job $job
            Log "ERROR" "在工作节点 $node 上安装 K3s agent 超时，请检查脚本或网络。"
        } else {
            # 获取作业输出和退出码
            $result = Receive-Job -Job $job
            if ($result -eq 0) {
                Log "INFO" "在工作节点 $node 上安装 K3s agent 成功。"
            } else {
                Log "ERROR" "在工作节点 $node 上安装 K3s agent 失败，退出码: $result"
            }
        }
        # 添加日志，标记在工作节点安装 K3s agent 完成
        Log "INFO" "在工作节点 $node 上安装 K3s agent 流程结束。"
    }
    
    # 验证安装
    try {
        wsl -d $masterNode -u root -e bash -c "k3s --version" | Out-Null
        Log "INFO" "K3s集群安装成功"
    } catch {
        Log "ERROR" "K3s安装失败"
        exit 1
    }
}

# 在每个节点上调用 K3s shell 执行命令，这里以查看节点状态为例
$nodes = Get-WSLInstances
foreach ($node in $nodes) {
    Log "INFO" "在节点 $node 上执行 K3s 命令..."
    $output = wsl -d $node -u root -e bash -c "k3s kubectl get nodes"
    Log "INFO" $output
}

# 主函数
function Main {
    Check-Admin
    
    Log "INFO" "=== 开始安装K3s ==="
    
    # 定义最大重试次数
    $maxRetries = 3

    # 安装 K3s 重试逻辑
    $retryCount = 0
    do {
        try {
            Install-K3s
            break
        } catch {
            $retryCount++
            if ($retryCount -lt $maxRetries) {
                Log "WARN" "K3s 安装失败，正在进行第 $retryCount 次重试..."
            } else {
                Log "ERROR" "K3s 安装失败，已达到最大重试次数。"
                exit 1
            }
        }
    } while ($true)
    
    Log "INFO" "=== K3s安装完成 ==="
    
    # 获取所有WSL实例
    $instances = Get-WSLInstances
    
    if ($instances.Count -eq 0) {
        Log "ERROR" "未找到匹配的WSL实例，无法获取状态信息。"
        return
    }
    
    $masterNode = $instances[0]
    Log "INFO" "K3s状态: wsl -d $masterNode -u root -e bash -c 'systemctl status k3s'"
    Log "INFO" "使用kubectl: wsl -d $masterNode -u root -e bash -c 'kubectl get nodes'"
    # 在Main函数最后添加
    Log "INFO" "正在等待集群就绪..."
    Start-Sleep -Seconds 30
    $kubeconfig = wsl -d $masterNode -u root -e bash -c "cat /etc/rancher/k3s/k3s.yaml"
    $masterIP = wsl -d $masterNode -u root -e bash -c "hostname -I | awk '{print \$1}'"
    $kubeconfig = $kubeconfig -replace "127.0.0.1", $masterIP
    $kubeconfig | Out-File "$env:USERPROFILE\.kube\config" -Force
}

# 在主节点安装完成后添加版本检查
$masterVersion = wsl -d $masterNode -u root -e bash -c "k3s --version"
Log "INFO" "主节点 K3s 版本: $masterVersion"

Main